package com.mysql.jdbc.cacheutils;

import java.sql.DriverManager;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.validation.constraints.Size;

import zhongqi.jdbc.dao.ConnectionDao;
import zhongqi.jdbc.dao.TableSqlList;

import com.google.common.collect.Collections2;
import com.mysql.jdbc.ResultSetInternalMethods;
import com.sun.crypto.provider.RSACipher;

import lombok.extern.slf4j.Slf4j;
import java.sql.Connection;

/**
 * @author  JYM
 * 2016-10-17 上午11:27:08
 */
@Slf4j
public class JdbcLruCache {
		
	//保存表名和rs表数据
	 private static Map<String, ResultSetInternalMethods> rsmap ;
	 
	//保存表名和历史sql（非查询）
	 //private static Map<String, String>  sqlMap;
	 private static Map<String, ArrayList<String>> sqlMap;
	 
	 static{
		         
		 rsmap=Collections.synchronizedMap(new LinkedHashMap<String, ResultSetInternalMethods>(3, 0.75f, true){
				protected boolean removeEldestEntry(Map.Entry eldest) {
					   if(!measureMemoryUse()){
						   return size() > (size()-1);
					   }else{
						   if(size() > 3){
							   consistency((String) eldest.getKey());
						   }
						   return  size() > 3;
					   }
		            }
			});
		    
		 sqlMap=new ConcurrentHashMap<String, ArrayList<String>>();
		     }
	  
	  
		/**
		 * 判断是否一个数据库的
		 * @param sql
		 * @param url
		 * @return
		 */
		public static boolean checkNotNullOrContainSql(String sql, String url) {
			// TODO Auto-generated method stub
			return false;
		}
		/**
		 * 判断是否包含这张表的数据
		 * @param sql的表名
		 * @return
		 */
		public static boolean checkNotNullOrContainCatalog(String catalog) {
			if (rsmap!=null && rsmap.containsKey(catalog)) {
				return true;
			}
			return false;
		}
		
		/**
		 * 缓存查询，获取resultset结果集
		 * @param sql
		 * @return
		 */
		public static ResultSet getResultSet(SqlParse sqlparse) {
			if (rsmap.containsKey(sqlparse.getTable())) {
				ResultSet rsResultSet = null;
				
				//拷贝缓存表的一个副本进行后续操作，否则改动的是缓存表本身数据
				try {
					rsResultSet = rsmap.get(sqlparse.getTable()).copyCacheResultset();
					
				} catch (SQLException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
				
				
				if (rsResultSet==null) {
					return null;
				}
				
				try {
					//((ResultSetInternalMethods) rsResultSet).changeRow();
					//缓存查询，构造查询语句所需要的结果
					((ResultSetInternalMethods) rsResultSet).create_result_for_select_sql(sqlparse);
					rsResultSet.beforeFirst();
				} catch (SQLException e) {
					e.printStackTrace();
				}
				return rsResultSet;
				
			}
			return null;
		}
		
		/**
		 * 插入语句
		 */
		public static void insert(SqlParse sqlparse) {
			if (rsmap.containsKey(sqlparse.getTable())) {
				ResultSet rsResultSet = null;
				
				//对缓存本身进行修改
				rsResultSet = rsmap.get(sqlparse.getTable());
									
				if (rsResultSet==null) {
					return;
				}
				
				try {
					//缓存插入，对缓存本身进行改动
					((ResultSetInternalMethods) rsResultSet).cache_insert_for_insert_sql(sqlparse);
					rsResultSet.beforeFirst();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
		
		
		/**
		 * 删除语句
		 */
		public static void delete(SqlParse sqlparse) {
			if (rsmap.containsKey(sqlparse.getTable())) {
				ResultSet rsResultSet = null;
				
				//对缓存本身进行修改
				rsResultSet = rsmap.get(sqlparse.getTable());
									
				if (rsResultSet==null) {
					return;
				}
				
				try {
					//缓存删除，对缓存本身进行改动
					((ResultSetInternalMethods) rsResultSet).cache_delete_for_delete_sql(sqlparse);
					rsResultSet.beforeFirst();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
		
		
		/**
		 * 更新语句
		 */
		public static void update(SqlParse sqlparse) {
			if (rsmap.containsKey(sqlparse.getTable())) {
				ResultSet rsResultSet = null;
				
				//对缓存本身进行修改
				rsResultSet = rsmap.get(sqlparse.getTable());
									
				if (rsResultSet==null) {
					return;
				}
				
				try {
					//缓存更新，对缓存本身进行改动
					((ResultSetInternalMethods) rsResultSet).cache_update_for_update_sql(sqlparse);
					rsResultSet.beforeFirst();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
		
		/**
		 * 存储表和SQL语句之间的关系，用于保存此表的历史非查询语句
		 * @param catalog
		 * @param sqlcache
		 */
		public static void putTbSql(String table, String sql) {
			ArrayList<String> tempSqlList = new ArrayList<String>();
			
			//如果没有这张表的缓存sql，才从中取出sql列表；否则新添加sql，然后把sql列表放入缓存sql中
			if(sqlMap.get(table) != null){
				tempSqlList = sqlMap.get(table);
			}

			tempSqlList.add(sql);
			sqlMap.put(table, tempSqlList);
		}
		
		
		public static ArrayList<String> getTbSql(String catalog) {
			ArrayList<String> sqlList = new ArrayList<String>();
			if (sqlMap.containsKey(catalog)) {
				 sqlList = sqlMap.get(catalog);
			}
			return sqlList;
			
		}
		/**
		 * 存储SQL语句的表名和结果集之间的关系
		 * @param catalog
		 * @param rs
		 */
		public static void putSqlRs(String catalog, ResultSetInternalMethods rs) {
			if(!measureMemoryUse()){
				//removeEldestEntry();
				 return;
			}
			if (measureMemoryUse()) {
			
				rsmap.put(catalog, rs);
			}
		}
		
		/**
		 * 从内存中移除最近最少使用的
		 * @return 
		 */
		/*private static boolean removeEldestEntry() {
			if (rsmap.size()>3  || ((rsmap.size()>(rsmap.size()-1)  &&  rsmap.size()>=0)) ){
				return true;
			}else{
				return false;
			}
			
			return rsmap.size()>3;
			
		}*/
		/**
		 * 删除缓存数据
		 * @param key
		 * @param currentCatalog 
		 */
		public static void RemoveFromMap(String catalog) {
			ResultSet rDate=rsmap.get(catalog);
			try {
				rDate.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}			
            rsmap.remove(catalog);
            consistency(catalog);
		}
		
		/**
		 * 一致性维护，当缓存表被删除时，对应的sql语句回写数据库，然后删除
		 */
		public static void consistency(String table) {
			String url="jdbc:mysql://127.0.0.1:3306/test";
		    String user="root";
		    String pwd="123456";
			
			ResultSet rDate=rsmap.get(table);
			try {
				rDate.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}			
            
			//如果sql缓存里没有对应的表，则直接跳出操作（因为没有sql，sqlmap里也没有记录）
			if(sqlMap.get(table) == null){
				log.info("-------一致性维护策略------");
				log.info("表" + table + "没有sql缓存，不用执行一致性维护策略");
				return;
			}
			
			try{
				Class.forName("com.mysql.jdbc.Driver");
				log.info("-------一致性维护策略------");
				log.info("开始连接数据库！");
				Connection con=DriverManager.getConnection(url, user, pwd);
			    Statement statement=con.createStatement();
			    log.info("数据库连接成功！");
			    log.info("执行SQL语句！");
			    ArrayList<String> sqlList = sqlMap.get(table);
			    sqlMap.remove(table);//保证缓存sql已移除
			    for(int i=0;i<sqlList.size();i++){
			    	statement.executeUpdate(sqlList.get(i));
			    }			    
			    log.info("------sql语句执行完毕！------");
			    statement.close();
				con.close();
			}catch (Exception ex){
		    	ex.printStackTrace();
		    }
            
		}
		
		/**
		 * 替换算法的规则
		 * 
		 */
		
		
		
		/**
		 * 计算当前JVM机内存空间大小
		 * 
		 */
		private static boolean measureMemoryUse() {
			boolean flag=true;
	        long total;
	        long free;
	        Runtime runtime = Runtime.getRuntime();
	        total = runtime.totalMemory();
	        free= runtime.freeMemory();
	        double tf=total*0.3;
	           //System.out.println(tf);
	           //System.out.println(free);
	        if (tf>free) {
	        	flag=false;
			}
	        return flag;
	    }
		
		//获取缓存表名
		public static List<String> getCacheTables(){
			Set<String> keySet = rsmap.keySet();
			ArrayList<String> tables = new ArrayList<String>();
			for(String key:keySet){
				tables.add(key);
			}
			return tables;
		}
		
		//获取缓存sql列表
		public static List<TableSqlList> getCacheTablesSql(){
			Set<String> keySet = rsmap.keySet();
			List<TableSqlList> tableSqlLists = new ArrayList<TableSqlList>();
			
			int maxLength = 0;
			for(String key:keySet){
				if(sqlMap.get(key) != null){
					if(sqlMap.get(key).size() > maxLength){
						maxLength = sqlMap.get(key).size();
					}
				}
			}
			
			for(int i=0;i<maxLength;i++){
				TableSqlList sqlList = new TableSqlList();
				int j = 1;
				for(String key:keySet){
						if(j == 1){
							sqlList.setTable1((sqlMap.get(key) != null&&sqlMap.get(key).size()>i)?sqlMap.get(key).get(i):null);
						}
						if(j == 2){
							sqlList.setTable2((sqlMap.get(key) != null&&sqlMap.get(key).size()>i)?sqlMap.get(key).get(i):null);
						}
						if(j == 3){
							sqlList.setTable3((sqlMap.get(key) != null&&sqlMap.get(key).size()>i)?sqlMap.get(key).get(i):null);
						}
					j++;					
				}
				tableSqlLists.add(sqlList);
			}
			return tableSqlLists;
		}
		

}
